package ltd.hxya.novel.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import ltd.hxya.novel.common.bean.Result;
import ltd.hxya.novel.common.constant.SortModeConstant;
import ltd.hxya.novel.common.to.book.BookTo;
import ltd.hxya.novel.common.vo.SearchParam;
import ltd.hxya.novel.search.feign.BookFeignService;
import ltd.hxya.novel.search.service.BookSearchService;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class BookSearchServiceImpl implements BookSearchService {
    @Autowired
    private RestHighLevelClient client;

    @Autowired
    private BookFeignService bookFeignService;
    @Override
    public Page<BookTo> searchBook(SearchParam searchParam) throws IOException {
        //从elasticsearch中模糊查询
        Boolean isAll = true;
        SearchRequest request = new SearchRequest();
        request.indices("novel");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //创建bookDesc,bookName,authorName字段查询
        if (!StringUtils.isEmpty(searchParam.getQueryWord())){
            MatchQueryBuilder bookDescMatchQuery = QueryBuilders.matchQuery("bookDesc", searchParam.getQueryWord());
            MatchQueryBuilder bookNameMatchQuery = QueryBuilders.matchQuery("bookName", searchParam.getQueryWord());
            MatchQueryBuilder authorNameMatchQuery = QueryBuilders.matchQuery("authorName", searchParam.getQueryWord());
            boolQueryBuilder.should(bookDescMatchQuery).should(bookNameMatchQuery).should(authorNameMatchQuery);
            isAll=false;

        }

        //判断查询条件是否为空，如果不为空，则添加到查询条件中
        if (searchParam.getIsEnd()!=null){
            TermQueryBuilder bookStatusQueryBuilder = QueryBuilders.termQuery("bookStatus", searchParam.getIsEnd());
            boolQueryBuilder.filter(bookStatusQueryBuilder);
            isAll=false;
        }
//        if (searchParam.getWorkDirection()!=null){
//            TermQueryBuilder workDirectionQueryBuilder = QueryBuilders.termQuery("workDirection", searchParam.getWorkDirection());
//            boolQueryBuilder.filter(workDirectionQueryBuilder);
//        }
        if (searchParam.getCategoryId()!=null){
            TermQueryBuilder catIdQueryBuilder = QueryBuilders.termQuery("catId", searchParam.getCategoryId());
            boolQueryBuilder.filter(catIdQueryBuilder);
            isAll=false;
        }
        if (!isAll){
            boolQueryBuilder.minimumShouldMatch(1);
        }
        if (StringUtils.isEmpty(searchParam.getUpdateTimeMin())){
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("lastIndexUpdateTime").gt(searchParam.getUpdateTimeMin());
            boolQueryBuilder.filter(rangeQueryBuilder);
        }

        if (searchParam.getWordCountMin()!=null&&searchParam.getWordCountMax()!=null){
            RangeQueryBuilder wordCountRangeQuery = QueryBuilders.rangeQuery("wordCount");
            if (searchParam.getWordCountMax()!=null){
                wordCountRangeQuery.lte(searchParam.getWordCountMax());
            }
            if (searchParam.getWordCountMin()!=null){
                wordCountRangeQuery.gt(searchParam.getWordCountMin());
            }
            boolQueryBuilder.filter(wordCountRangeQuery);
        }


        searchSourceBuilder.query(boolQueryBuilder);

        FieldSortBuilder sortBuilder = null;

        //排序
        if (SortModeConstant.LAST_CHAPTER_UPDATE_TIME_DESC.equals(searchParam.getSort())){
            //根据时间排序
            sortBuilder = SortBuilders.fieldSort("lastIndexUpdateTime").order(SortOrder.DESC);
        }
        if (SortModeConstant.VISIT_COUNT_DESC.equals(searchParam.getSort())){
            //根据访问量排序
            sortBuilder = SortBuilders.fieldSort("visitCount").order(SortOrder.DESC);
        }
        if (SortModeConstant.WORD_COUNT_DESC.equals(searchParam.getSort())){
            //根据字数排序
            sortBuilder = SortBuilders.fieldSort("wordCount").order(SortOrder.DESC);
        }
        if (sortBuilder!=null){
            searchSourceBuilder.sort(sortBuilder);
        }

        //高亮

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        highlightBuilder.field("bookDesc");
        highlightBuilder.field("bookName");
        highlightBuilder.field("authorName");
        searchSourceBuilder.highlighter(highlightBuilder);

        searchSourceBuilder.from((searchParam.getPage()-1)*searchParam.getSize()).size(searchParam.getSize());

        //将searchSourceBuilder添加到request资源中

        request.source(searchSourceBuilder);

        //执行查询代码
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);

        //取出查询到的数据
        Page<BookTo> bookToPage = outSearchData(response,searchParam);
        return bookToPage;
    }

    @Override
    public void renewEs() {
        //更新es中的数据
        Result<List<BookTo>> listResult = bookFeignService.listAllBook();
        List<BookTo> data = listResult.getData();
        if (CollectionUtils.isEmpty(data)){
            return;
        }
        BulkRequest bulkRequest = new BulkRequest();
        data.forEach(book -> {
            IndexRequest request = new IndexRequest();
            request.index("novel").id(book.getId());
            String json = JSON.toJSONString(book);
            request.source(json, XContentType.JSON);
            bulkRequest.add(request);
        });
        try {
            client.bulk(bulkRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    public Page<BookTo> outSearchData(SearchResponse response,SearchParam searchParam) {
        Page<BookTo> bookToPage = new Page<>();
        SearchHits hits = response.getHits();
        bookToPage.setTotal(hits.getTotalHits().value);
        bookToPage.setPages(bookToPage.getTotal()/searchParam.getSize()>100?100:bookToPage.getTotal()/searchParam.getSize());
        bookToPage.setSize(searchParam.getSize());
        bookToPage.setCurrent(searchParam.getPage());
        outSearchData(response, bookToPage);
        return bookToPage;
    }

    public void outSearchData(SearchResponse response, Page<BookTo> bookToPage) {
        SearchHit[] searchHits = response.getHits().getHits();
        List<BookTo> bookTos = Arrays.stream(searchHits).map(searchHit -> {
            String sourceAsString = searchHit.getSourceAsString();
            BookTo bookTo = JSON.parseObject(sourceAsString, new TypeReference<BookTo>() {
            });
            Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
            HighlightField bookDescHighlightField = highlightFields.get("bookDesc");
            HighlightField bookNameHighlightField = highlightFields.get("bookName");
            HighlightField authorNameHighlightField = highlightFields.get("authorName");
            if (bookDescHighlightField!=null){
                Text[] bookDescValues = bookDescHighlightField.getFragments();
                String bookDesc ="";
                for (Text bookDescValue : bookDescValues) {
                    bookDesc=bookDesc+bookDescValue;
                }
                bookTo.setBookDesc(bookDesc);
            }
            if (bookNameHighlightField!=null){
                Text[] bookNameValues = bookNameHighlightField.getFragments();
                String bookName = "";
                for (Text bookNameValue : bookNameValues) {
                    bookName = bookName + bookNameValue;
                }
                bookTo.setBookName(bookName);
            }
           if (authorNameHighlightField!=null){
               Text[] authorNameValues = authorNameHighlightField.getFragments();
               String authorName = "";
               for (Text authorNameValue : authorNameValues) {
                   authorName = authorName + authorNameValue;
               }
               bookTo.setAuthorName(authorName);
           }
            return bookTo;

        }).collect(Collectors.toList());
        bookToPage.setRecords(bookTos);
    }
}
